---
id: installation
title: Installation
---

<center>
	<div
		data-ea-publisher="immerjs"
		data-ea-type="image"
		className="horizontal bordered"
	></div>
</center>

Immer can be installed as a direct dependency, and will work in any ES5 environment:

- Yarn: `yarn add immer`
- NPM: `npm install immer`
- CDN: Exposed global is `immer`
  - Unpkg: `<script src="https://unpkg.com/immer"></script>`
  - JSDelivr: `<script src="https://cdn.jsdelivr.net/npm/immer"></script>`
  - ⚠️ When using a CDN, it is best to check the url in your browser and see what version it resolves to, so that your users aren't accidentally served a newer version in the future when updates are release. So use a url like: https://unpkg.com/immer@6.0.3/dist/immer.umd.production.min.js instead. Substitute `production.min` with `development` in the URL for a development build.

## Pick your Immer version

_This section only applies to version 6 and later_

To make sure Immer is as small as possible, features that are not required by every project has been made opt-in, and have to be enabled explicitly. This ensures that when bundling your application for production, unused features don't take any space.

The following features can be opt-in to:

| Feature | Description | Method to call |
| --- | --- | --- |
| [ES2015 Map and Set support](./complex-objects.md) | To enable Immer to operate on the native `Map` and `Set` collections, enable this feature | `enableMapSet()` |
| [JSON Patch support](./patches.mdx) | Immer can keep track of all the changes you make to draft objects. This can be useful for communicating changes using JSON patches | `enablePatches()` |

For example, if you want to use `produce` on a `Map`, you need to enable this feature once during the start of your application:

```typescript
// In your application's entrypoint
import {enableMapSet} from "immer"

enableMapSet()

// ...later
import {produce} from "immer"

const usersById_v1 = new Map([
	["michel", {name: "Michel Weststrate", country: "NL"}]
])

const usersById_v2 = produce(usersById_v1, draft => {
	draft.get("michel").country = "UK"
})

expect(usersById_v1.get("michel").country).toBe("NL")
expect(usersById_v2.get("michel").country).toBe("UK")
```

Vanilla Immer kicks in at ~3KB gzipped. Every plugin that is enabled adds < 1 KB to that. The breakdown is as follows:

```
Import size report for immer:
┌───────────────────────┬───────────┬────────────┬───────────┐
│        (index)        │ just this │ cumulative │ increment │
├───────────────────────┼───────────┼────────────┼───────────┤
│ import * from 'immer' │   5033    │     0      │     0     │
│        produce        │   3324    │    3324    │     0     │
│     enableMapSet      │   4030    │    4039    │    715    │
│     enablePatches     │   4112    │    4826    │    787    │
└───────────────────────┴───────────┴────────────┴───────────┘
(this report was generated by npmjs.com/package/import-size)
```

## Immer on older JavaScript environments?

By default `produce` tries to use proxies for optimal performance. However, on older JavaScript engines `Proxy` is not available. For example, when running Microsoft Internet Explorer or React Native (if < v0.59 or when using the Hermes engine on React Native < 0.64) on Android. In such cases, Immer will fallback to an ES5 compatible implementation which works identically, but is a bit slower.

- Since version 6, support for the fallback implementation has to be explicitly enabled by calling `enableES5()`.
- Version 10 drops the fallback implementation fully, and cannot be used in browsers / engines that don't support Proxy.
